<?php


namespace plugin\colecron\app\service;


use Exception;
use support\exception\BadException;
use support\Log;
use Throwable;

class ClientService
{

    private $client;
    /**
     * @var self
     */
    protected static $instance = null;

    const ADDRESS = "tcp://127.0.0.1:12345";
    const TIMEOUT = 10; //超时时间 10s

    public function __construct()
    {
        $this->client = $this->reconnect(self::TIMEOUT, 1);
    }

    /**
     * 重连
     * @param $timeout
     * @param $retries
     * @return resource
     * @throws BadException
     */
    function reconnect($timeout, $retries)
    {
        $attempts = 0;
        while ($attempts < $retries) {
            $connection = @stream_socket_client(self::ADDRESS, $errno, $errstr, $timeout);
            if ($connection) {
                return $connection; // 成功连接后返回资源句柄
            }
            // 等待一段时间后再尝试
            usleep(500000); // 等待0.5秒
            $attempts++;
        }
        // 如果达到最大尝试次数仍然失败，抛出异常
        throw new BadException("无法链接cron服务器");
    }

    public static function instance()
    {
        if (!static::$instance) {
            static::$instance = new static();
        }
        return static::$instance;
    }

    public function send($param)
    {
        fwrite($this->client, json_encode($param) . "\n"); // text协议末尾有个换行符"\n"
        $result = fgets($this->client, 10240000);
        return json_decode($result);
    }

    /**
     * @param array $param
     * @return mixed
     */
    public function request(array $param)
    {
        try {
            $result = $this->send($param);
        } catch (Throwable $exception) {
            Log::error("执行cron操作异常,进行重连: " . $exception->getMessage());
            try {
                $this->client = $this->reconnect(self::TIMEOUT, 5);
                $result = $this->send($param);
            } catch (Exception $exception) {
                Log::error("执行cron操作异常,重连失败: " . $exception->getMessage());
            }
        }
        return $result;
    }

}